<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <title>动态变换运行时上下文</title>
    <script type="text/javascript">

        var Obj = {
            name: 1,
            speeking: function () {
                console.log(this.name);
            },
            callback: function () {

            }


        };
        //分析：在这个对象中this属于隐式绑定(呵呵)
        Obj.name;
        console.log(window.name);

        //Obj 与 Person 对照 就能看出Function与Object之间的关联关系

        function Person() {
            //属性(函数在New后实例化为一个对象，对象的属性就是this声明的这些对象)
            this._name = "";
            this._age = 0;

            //方法
            /**
             * 讲话
             * @private
             */
            this._speeking = function () {
                console.log("Hello,I'm " + this._name + "," + this._age + " years old!");
            };
        }

        function Student(name, age, gradle) {
            //实现上下问替换
            //此时当前下上下文中的this绑定在Student中(前提是不能执行一些绑定丢失的操作),
            //Function.call(obj,arg);
            //obj这个对象将替换Function的上下文this对象
            //this上下文的绑定有很多限制条件
            Person.call(this, arguments);

            this._speeking = function () {
                console.log("方法的重写");
            };
        }

        var zhangsan = new Student("zhangsan", "18", "一年级");
        zhangsan._speeking();

        console.log("/////////////////////////分割线/////////////////////////")
        //this的4中绑定规则
        //1、默认绑定：默认绑定就是this绑定到window对象上(非严格模式下)
        this.aaa = "默认绑定就是this绑定到window对象上(非严格模式下)";
        console.log(window.aaa);

        //函数在独立运行时,独立函数并且在独立调用时
        function foo1() {
            //默认在次函数不是独立调用时this代表的是此函数的上下文
            //那么换句话说如果如果函数在某些特定情况下会影响函数的绑定模式
            //那么此处的独立函数在被独立调用时，this的上文就不是值的当前的函数上下文，而是默认绑定表示的window
            this.aaaa = "独立函数在独立调用时，this是默认绑定";
        }
        foo1();
        console.log(window.aaaa);

        function foo() {
            function inner() {
                this.aaaaa = "此函数的一个嵌套函数，在此函数中使用this，this代指inner函数上下文，" +
                        "但是如果在次函数的外部独立调用了次函数，那么次函数的绑定就会发生变化";
                console.log(this.aaaaa);
            }

            inner();
        }
        foo(); //运行
        console.log(window.aaaaa);

        window.data = "默认绑定";


        (function () {
            console.log(this.data);
        }());

        function handler() {
            (function () {
                console.log(this.data);
            }());
        }

        console.log("/////////////////////////隐式绑定分割线/////////////////////////")
        //2、隐式绑定：
        //一般的，在对象中申明的函数，被调用是，this隐式绑定到该对象；

        var name = "我的全局的this绑定参数";
        var YS = {
            name: "Ailsabe-CMS",
            showName: function () {
                console.log(this.name);
            }
        };
        YS.showName();

        //隐式绑定中，最主要的就是隐式丢失，什么情况会造成隐式丢失呢？
        // //a、函数别名，就是为对象中声明的函数取一个别名，再去调用这个别名，那么就会造成隐式丢失
        //
        var showName = YS.showName;
        showName();
        //
        // //b、参数传递，将对象中的函数已一个参数的方式传递给另一个函数，那么就会造成隐式丢失
        function showName(callBack) {
            callBack();
        }
        showName(YS.showName);
        //
        // //c、内置函数，内置函数与参数传递是一个意思，只是内置函数是一些特殊的函数，又系统或者框架给实现完成了
        //
        setTimeout(YS.showName, 1000); // 理解this最好是理解javascript的编译原理
        // //d、间接引用，说白了就是对象与对象见的赋值
        // 
        function println() {
            console.log(this.parameter);
        }

        var parameter = "全局的this绑定参数parameter";
        var o = {parameter: "o", println: println};
        var p = {parameter: "p"};

        p.println = o.println;
        (p.println = o.println)();
        // 从上面的两个操作来好像是一样的，但是由于
        p.println();  //
        console.log("/////////////////////////显式绑定分割线/////////////////////////")
        //3、显式绑定：通过call(),apply(),bind()方法把对象绑定到this，叫做显示绑定，对于被调用的函数来说叫做间接调用；
        var index = 0;
        function setIndex(){
            console.log(this.index);
        }
        var obj1 = {
            index:1
        };
        var obj2 = {
            index:2
        };
        setIndex.call(obj1);//1
        setIndex.call(obj2);//2
        //硬绑定 当使用硬绑定时，this绑定就不会被更改，丢失神马的再也不用担心了(继承？)
        var bar= function(){
            this.index = 5;
            setIndex.call(this);
        }
        bar();//5
        //4、NEW绑定：

        //
    </script>
</head>

<body>

</body>

</html>